/*

    This file is part of Hometree.

    Hometree is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Hometree is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Hometree.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2011,2012 Roman Held

*/

/********************************************************************\
                            Includes
\********************************************************************/
#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QTcpServer>
#include "htr/mansock.h"
#include "htr/htrlog.h"
#include "htrsprovider.h"
#include "htrssession.h"

/********************************************************************\
                            Macros
\********************************************************************/
#define IDENT "PROV"
#define TERM_SIGNAL_INTERVAL 1000

/********************************************************************\
                            Static-Members
\********************************************************************/
bool HtrsProvider::sTermSignalPending = false;

/********************************************************************\
                            Implementation
\********************************************************************/
/*--------------------------------------------------------------------
*/
HtrsProvider::HtrsProvider()
  : QObject(), mInternalSession(&mResources)
{
  connect(this, SIGNAL(sessionCount(int)),
          &mInternalSession, SLOT(updateSessionCount(int)));
  mShutdownActive = false;

  // Shutdown on SIGTERM:
  QTimer *t = new QTimer(this);
  connect(t, SIGNAL(timeout()), this, SLOT(testTermSignal()));
  t->start(TERM_SIGNAL_INTERVAL);
}

/*--------------------------------------------------------------------
*/
HtrsProvider::~HtrsProvider()
{
  if (!mShutdownActive)
    shutdown();
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::startServer()
{
  mShutdownActive = false;
  connect(&mServer, SIGNAL(newConnection()),
          this, SLOT(newClient()));

  // TODO: Config:
  QString iface = "127.0.0.1";
  int     port  = 7000;
  if (mServer.listen(QHostAddress(iface),port))
   HtrLog::instance()->info(IDENT,QString("Listening on %1:%2").arg(iface).arg(port));
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::shutdown(const QString &msg)
{
  HtrLog::instance()->info(IDENT,QString("Shutdown (Reason:\"%1\")").arg(msg));
  mServer.close();
  mShutdownActive = true;

  foreach(HtrsSession *sess,mSessions) {
    if (!msg.isEmpty())
      sess->sendSms(msg);
    sess->shutdown();
  }

  handleShutdownSessions();
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::newClient()
{
  if (mShutdownActive) { // ASSERT?
    mServer.nextPendingConnection()->deleteLater();
    return;
  }

  HtrsSession *newSession = new HtrsSession(mServer.nextPendingConnection(),
                                      &mResources);
  HtrLog::instance()->info(IDENT,"New Session created");

  // Auto-Close and Shutdown:
  connect(newSession, SIGNAL(destroyed(QObject*)),
          this, SLOT(sessionDestroyed(QObject*)));

  mSessions << newSession;
  emit sessionCount(mSessions.count());
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::sessionDestroyed(QObject *obj)
{
  HtrsSession *sess = static_cast<HtrsSession*>(obj);
  if (mSessions.contains(sess)) {
    mSessions.removeAll(sess);
    HtrLog::instance()->info(IDENT,"Session removed");
    emit sessionCount(mSessions.count());
    handleShutdownSessions();
  }
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::testTermSignal()
{
  if (sTermSignalPending && !mShutdownActive)
    shutdown("killed by SIGTERM");
}

/*--------------------------------------------------------------------
*/
void HtrsProvider::handleShutdownSessions()
{
  if (!mShutdownActive)
    return;
  if (mSessions.count() == 0) {
    HtrLog::instance()->info(IDENT,"Halted");
    emit providerHalted();
  }
}
